package com.dxy.netty.groupchat;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;

import java.time.LocalDateTime;

/**
 * @Description netty服务器处理器
 * @Author dangxianyue
 * @Date 2023/1/6 10:39
 */
public class NettyGroupChatServerHandler extends SimpleChannelInboundHandler<String> {

    // 定义一个 channel 组，用于管理channel
    // GlobalEventExecutor.INSTANCE 是全局事件执行器，是一个单例
    private static final ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    // 读取数据并转发
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        // 获取当前channel
        Channel channel = ctx.channel();
        // 遍历 channelGroup， 根据不同情况 回送不同消息
        channelGroup.forEach(otherChannel-> {
            if (channel != otherChannel) { // 非当前channel， 直接转发
                otherChannel.writeAndFlush("["+ LocalDateTime.now() +"]"+ "客户端" + channel.remoteAddress() + "说：" + msg + "\n");
            } else { // 回显自己发送的消息给自己
                channel.writeAndFlush("["+ LocalDateTime.now() +"]"+ "自己说：" + msg + "\n");
            }
        });
    }

    // 一旦连接建立，第一个被执行
    // 将当前channel 添加到channelGroup
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        // 把客户端加入群组的信息发送到其他客户端
        channelGroup.writeAndFlush("["+ LocalDateTime.now() +"]"+ "客户端 " + channel.remoteAddress() + " 加入聊天");
        // 把当前channel 添加到 channel 组
        channelGroup.add(channel);
    }

    // 表示 channel 处于活动状态， 提示 xx 上线
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("["+ LocalDateTime.now() +"]"+ "客户端 " + ctx.channel().remoteAddress() + " 上线了");
    }

    // 表示 channel 处于离线状态， 提示 xx 离线
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("["+ LocalDateTime.now() +"]"+ "客户端 " + ctx.channel().remoteAddress() + " 离开了");
    }

    // 断开连接，把xx客户离开的信息推送给其他在线客户
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        channelGroup.writeAndFlush("["+ LocalDateTime.now() +"]"+ "客户端 " + channel.remoteAddress() + " 离开了");
        System.out.println("channelGroup.size() = " + channelGroup.size());
    }

    // 发送异常如何处理
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        // 关闭通道
        ctx.close();
    }
}
